package com.qq.vip.mikuPy2001.bukkit.gui.privater;

import com.qq.vip.mikuPy2001.bukkit.GUI;
import com.qq.vip.mikuPy2001.bukkit.gui.ViewListener;
import com.qq.vip.mikuPy2001.bukkit.gui.Windows;
import com.qq.vip.mikuPy2001.bukkit.gui.WindowsView;
import com.qq.vip.mikuPy2001.bukkit.gui.model.Button;
import com.qq.vip.mikuPy2001.bukkit.gui.model.EditBox;
import com.qq.vip.mikuPy2001.bukkit.gui.util.Message;
import com.qq.vip.mikuPy2001.bukkit.gui.model.Module;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;

/**
 *
 * @author MukiPy2001
 */
public class DefaultWindowsView implements Listener, WindowsView {

    private final LinkedHashMap<String, Module> modules = new LinkedHashMap<>();
    private final HashMap<Integer, Module> invShow = new HashMap<>();
    private final String player;
    private final HashSet<ViewListener> listeners;
    private final Inventory inv;
    private final InventoryView invView;
    private final Windows windows;

    private final ItemStack background;
    private final HashMap<Integer, ItemStack> backgrounds;

    private BukkitTask runTask;
    private boolean close = false;

    /**
     * 为指定玩家打开一个界面. 直接调用本构造函数将无法在服务器关闭时妥善处理箱子内容.
     *
     * @param windows
     * @param player
     * @see Windows#open(org.bukkit.entity.Player)
     */
    public DefaultWindowsView(Windows windows, Player player) {
        //赋值
        this.windows = windows;
        this.player = player.getName();
        this.listeners = (HashSet<ViewListener>) windows.getListeners().clone();
        this.background = windows.getBackground();
        this.backgrounds = (HashMap<Integer, ItemStack>) windows.getBackgrounds().clone();

        for (Map.Entry<String, Module> entry : windows.getModules().entrySet())
            modules.put(entry.getKey(), ((PrivateModule) entry.getValue()).clone(this));

        // 预摆放控件
        int max = 0;
        for (Module moudle : modules.values()) {
            if (invShow.containsKey(moudle.getIndex()))
                continue;
            if (moudle.CanShowOnCreate())
                invShow.put(moudle.getIndex(), moudle);
            if (max < moudle.getIndex())
                max = moudle.getIndex();
        }
        // 预摆放背景
        for (Map.Entry<Integer, ItemStack> entry : backgrounds.entrySet())
            if (max < entry.getKey())
                max = entry.getKey();
        // 计算箱子大小
        int line = windows.getSize() < 1 ? (max / 9 + 1) * 9 : windows.getSize() * 9;
        if (line > 6 * 9) {
            line = 6 * 9;
            // 删除超出界面的控件
            for (Collection<Module> module : new Collection[]{modules.values(), invShow.values()})
                for (Iterator<Module> it = module.iterator(); it.hasNext();)
                    if (it.next().getIndex() >= line)
                        it.remove();
            // 删除超出界面的背景
            for (Iterator<Map.Entry<Integer, ItemStack>> iterator = backgrounds.entrySet().iterator(); iterator.hasNext();)
                if (iterator.next().getKey() >= line)
                    iterator.remove();
        }
        // 生成箱子
        inv = Bukkit.createInventory(player, line, ChatColor.translateAlternateColorCodes('&', windows.getTitle()));
        // 激活控件,摆放背景
        for (int i = 0; i < line; i++) {
            Module module = invShow.get(i);
            if (module != null) {
                inv.setItem(i, module.getItemStack());
                ((PrivateModule) module).enable0();
            } else {
                // 背景
                ItemStack background_t = backgrounds.get(i);
                if (background_t != null)
                    inv.setItem(i, background_t);
                else
                    inv.setItem(i, background);
            }
        }
        player.closeInventory();
        // 注册事件
        Bukkit.getPluginManager().registerEvents(this, GUI.getInstance());
        // 打开箱子
        invView = player.openInventory(inv);
        Message.debug(player + "打开了" + inv.getTitle() + ChatColor.RESET + ", 大小为: " + line / 9);
    }

    @Override
    public void enable(String module) {
        if (close)
            return;
        // 获取module
        Module newModule = modules.get(module);
        if (newModule == null) {
            Message.debug("忽略|激活|ID不存在:" + module + ", 界面拥有者: " + player);
            return;
        }
        Module oldModule = invShow.get(newModule.getIndex());
        // 判断是否已经显示
        if (oldModule == newModule) {
            Message.debug("忽略|激活|控件已经激活:" + module + ", 界面拥有者: " + player);
            return;
        }
        // 注销原有module
        if (oldModule != null)
            ((PrivateModule) oldModule).disable0();
        // 显示新的modle
        invView.setItem(newModule.getIndex(), newModule.getItemStack());
        invShow.put(newModule.getIndex(), newModule);
        ((PrivateModule) newModule).enable0();
        Message.debug("激活|控件激活成功:" + newModule + ", 界面拥有者: " + player);
    }

    @Override
    public void disable(String module) {
        if (close)
            return;
        // 获取module
        Module wantdisable = modules.get(module);
        if (wantdisable == null)
            return;
        // 判断是否显示
        Module show = invShow.get(wantdisable.getIndex());
        if (show != wantdisable)
            return;
        // 取消激活
        ((PrivateModule) show).disable0();
        invShow.remove(show.getIndex());
        // 设置背景
        ItemStack get = backgrounds.get(show.getIndex());
        invView.setItem(show.getIndex(), get == null ? background : get);
        Message.debug("取消激活了" + show);
    }

    @Override
    public void update(Module module) {
        if (!module.isEnable()) {
            Message.debug("忽略|更新|此控件未激活" + module + ", 界面拥有者: " + player);
            return;
        }
        if (invShow.get(module.getIndex()) != module) {
            Message.debug("忽略|更新|不是这个窗口的控件" + module.getView() + ", 界面拥有者: " + player);
            return;
        }
        if (!((PrivateModule) module).isChange0()) {
            Message.debug("忽略|更新|物品未发生变化" + module + ", 触发者: " + player);
            return;
        }
        update0(module, module.getItemStack0());
    }

    @Override
    public void update(int index) {
        Module module = invShow.get(index);
        if (module == null) {
            Message.debug("忽略|更新|是背景, 界面拥有者: " + player);
            return;
        }
        if (!((PrivateModule) module).isChange0()) {
            Message.debug("忽略|更新|物品未发生变化" + module + ", 触发者: " + player);
            return;
        }
        update0(module, inv.getItem(index));
    }

    private void update0(Module module, ItemStack item) {

        // 发布事件
        for (ViewListener listener : listeners)
            try {
                item = listener.itemStackChange(this, module, item);
            } catch (Throwable e) {
                Message.warn("a warn in itemStackChange(can Change) Eve ", e);
            }
        // 修改
        ((PrivateModule) module).setItemStack0(item);
        invView.setItem(module.getIndex(), item);

        //通知变化
        for (ViewListener listener : listeners)
            try {
                listener.itemStackChange(this, module);
            } catch (Throwable e) {
                Message.warn("a warn in itemStackChange(can't Change) Eve ", e);
            }

        Message.debug("修改|更新|" + module + ", 界面拥有者: " + player);
    }

    @Override
    public void addListener(ViewListener listener) {
        if (close)
            return;
        if (listener == null)
            throw new NullPointerException("listener is null");
        listeners.add(listener);
    }

    @Override
    public Player getPlayer() {
        return Bukkit.getPlayer(this.player);
    }

    @Override
    public Module getModule(String ID) {
        return modules.get(ID);
    }

    @Override
    public Windows getWindows() {
        return windows;
    }

    /**
     * 点击
     *
     * @param e
     */
    @EventHandler(ignoreCancelled = true)
    public void onInvClick(InventoryClickEvent e) {
        if (!player.equals(e.getWhoClicked().getName()))
            return;
        if (close) {
            close();
            return;
        }
        // 过滤双击
        if (e.getClick() == ClickType.DOUBLE_CLICK)
            return;

        int clickInt = e.getRawSlot();

        // 点击背包
        if (clickInt >= inv.getSize()) {
            // 不是Shift点击
            if (!e.isShiftClick()) {
                Message.debug("无视|点击|背包, 触发者: " + player);
                return;
            }
        } else if (clickInt < 0) {
            // 点击箱子外部灰色区域
            Message.debug("无视|点击|灰色区域, 触发者: " + player);
            return;
        }
        // Shift点击背包(会将物品移动至界面)
        if (clickInt >= inv.getSize()) {
            Message.debug("点击|Shift|背包(会将物品移动至界面中空着的编辑框), 触发者: " + player);
            tick();
        } else {
            // 在界面中的操作
            Module clickModule = invShow.get(clickInt);
            if (clickModule instanceof EditBox) {
                Message.debug("点击|编辑框|" + clickModule + ", 触发者: " + player);
                tick();
            } else if (clickModule instanceof Button) {
                Message.debug("点击|按钮|" + clickModule + ", 触发者: " + player);
                e.setCancelled(true);
                for (ViewListener listener : listeners)
                    try {
                        listener.onClick(this, clickModule);
                    } catch (Throwable e1) {
                        Message.warn("a warn in onClose Eve ", e1);
                    }
            } else {
                Message.debug("无视|点击|界面背景, 触发者: " + player);
                e.setCancelled(true);
            }
        }
    }

    /**
     * 拖动
     *
     * @param e
     */
    @EventHandler(ignoreCancelled = true)
    public void onInvDrag(InventoryDragEvent e) {
        if (!player.equals(e.getWhoClicked().getName()))
            return;

        if (close) {
            close();
            return;
        }

        for (Integer rawSlot : e.getRawSlots())
            // 拖动的物品涉及某些编辑框
            if (rawSlot < inv.getSize() && rawSlot > 0) {
                Message.debug("拖动|一个或多个编辑框, 触发者: " + player);
                tick();
                break;
            }
    }

    /**
     * 箱子关闭
     *
     * @param e
     */
    @EventHandler
    public void onInvClose(InventoryCloseEvent e) {
        if (!player.equals(e.getPlayer().getName()))
            return;
        Message.debug("关闭|箱子关闭, 触发者: " + player);
        close();

    }

    /**
     * 玩家退出
     *
     * @param e
     */
    @EventHandler
    public void onQuit(PlayerQuitEvent e) {
        if (!player.equals(e.getPlayer().getName()))
            return;
        Message.debug("关闭|退出游戏, 触发者: " + player);
        close();

    }

    /**
     * 玩家死亡
     *
     * @param e
     */
    @EventHandler
    public void onDeath(PlayerDeathEvent e) {
        if (!player.equals(e.getEntity().getName()))
            return;
        Message.debug("关闭|死亡, 触发者: " + player);
        close();
    }

    @Override
    public void close() {
        close = true;
        // 这里需要先移除监听器,然后才能关闭玩家箱子, 否则会引发死循环
        // 已经避免
        HandlerList.unregisterAll(this);
        // 发布事件
        for (ViewListener listener : listeners)
            try {
                listener.onClose(this);
            } catch (Throwable e) {
                Message.warn("a warn in onClose Eve ", e);
            }
        @SuppressWarnings("LocalVariableHidesMemberVariable")
        Player player = Bukkit.getPlayer(this.player);
        // 关闭玩家箱子
        if (player.getOpenInventory().equals(invView))
            player.closeInventory();
        // 注销各个控件
        for (Module value : invShow.values())
            value.disable();
        player.updateInventory();
    }

    @Override
    public boolean isClose() {
        return close;
    }

    private void tick() {
        if (runTask == null) {
            runTask = Bukkit.getScheduler().runTask(GUI.getInstance(), new Runnable() {
                @Override
                public void run() {
                    Message.debug("----刷新开始----");
                    for (Map.Entry<Integer, Module> entry : invShow.entrySet())
                        update(entry.getValue().getIndex());
                    Message.debug("----刷新完毕----");
                    runTask = null;
                }
            });
        }
    }

    /**
     * 获取指定位置上的物品
     *
     * @param index
     * @return
     */
    @Override
    public ItemStack getItem(int index) {
        return inv.getItem(index);
    }
}
